﻿namespace Fiddler
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Windows.Forms;

    public class UINotifyList : Form
    {
        private CheckBox cbEnabled;
        private ComboBox cbxNotifyLevel;
        private IContainer components;
        private static UINotifyList frmProtocolViolationList = null;
        private ListBox lvItems;
        private static object oLock = new object();
        private static List<NotifyItem> qWarningsToAdd = new List<NotifyItem>();
        private static StringFormat sfIDColumn = new StringFormat();

        public UINotifyList()
        {
            this.InitializeComponent();
            base.Icon = Utilities.GetIconFromImage(FiddlerApplication.UI.imglSessionIcons.Images[12]);
            base.Size = new Size(FiddlerApplication.Prefs.GetInt32Pref("fiddler.ui.httperror.Width", base.Width), FiddlerApplication.Prefs.GetInt32Pref("fiddler.ui.httperror.Height", base.Height));
            base.StartPosition = FormStartPosition.Manual;
            base.Location = new Point(FiddlerApplication.Prefs.GetInt32Pref("fiddler.ui.httperror.Left", 100), FiddlerApplication.Prefs.GetInt32Pref("fiddler.ui.httperror.Top", 100));
            Screen screen = Screen.FromRectangle(base.DesktopBounds);
            Rectangle rectangle = Rectangle.Intersect(base.DesktopBounds, screen.WorkingArea);
            if (rectangle.IsEmpty || ((rectangle.Width * rectangle.Height) < ((0.2 * base.Width) * base.Height)))
            {
                base.SetDesktopLocation(screen.WorkingArea.Left + 20, screen.WorkingArea.Top + 20);
            }
            sfIDColumn.Alignment = StringAlignment.Center;
            sfIDColumn.LineAlignment = StringAlignment.Center;
            this.lvItems.Font = new Font(this.lvItems.Font.FontFamily, CONFIG.flFontSize);
            this.lvItems.DrawItem += new DrawItemEventHandler(this.lvItems_DrawItem);
            this.lvItems.MeasureItem += new MeasureItemEventHandler(this.lvItems_MeasureItem);
            this.cbEnabled.Checked = CONFIG.bReportHTTPErrors;
            this.cbxNotifyLevel.SelectedIndex = CONFIG.bReportHTTPLintErrors ? 1 : 0;
            this.cbxNotifyLevel.SelectedIndexChanged += new EventHandler(this.cbxNotifyLevel_SelectedIndexChanged);
        }

        private void actDoInspect()
        {
            if (this.lvItems.SelectedItem != null)
            {
                int iID = ((NotifyItem)this.lvItems.SelectedItem).iSessionID;
                FiddlerApplication.UI.actSelectSessionsMatchingCriteria(1, delegate(Session oS)
                {
                    return oS.id == iID;
                });
                if (1 == FiddlerApplication.UI.lvSessions.SelectedCount)
                {
                    FiddlerApplication.UI.lvSessions.SelectedItems[0].EnsureVisible();
                    FiddlerApplication.UI.lvSessions.SelectedItems[0].Focused = true;
                    FiddlerApplication.UI.actInspectSession();
                    FiddlerApplication.UI.lvSessions.Focus();
                }
            }
        }

        private void cbEnabled_Click(object sender, EventArgs e)
        {
            CONFIG.bReportHTTPErrors = this.cbEnabled.Checked;
        }

        private void cbxNotifyLevel_SelectedIndexChanged(object sender, EventArgs e)
        {
            CONFIG.bReportHTTPLintErrors = 1 == this.cbxNotifyLevel.SelectedIndex;
            FiddlerApplication.Prefs.SetBoolPref("fiddler.Lint.HTTP", CONFIG.bReportHTTPLintErrors);
        }

        public static void ClearAllErrors()
        {
            UINotifyList frmProtocolViolationList;
            lock (oLock)
            {
                frmProtocolViolationList = UINotifyList.frmProtocolViolationList;
            }
            if (frmProtocolViolationList != null)
            {
                try
                {
                    FiddlerApplication.UIInvokeAsync(new MethodInvoker(frmProtocolViolationList.ClearUIOnMainThread), null);
                }
                catch
                {
                }
            }
        }

        private void ClearUIOnMainThread()
        {
            if (frmProtocolViolationList != null)
            {
                frmProtocolViolationList.lvItems.Items.Clear();
                frmProtocolViolationList.Text = "Protocol Violation Report";
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (this.components != null))
            {
                this.components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            this.cbEnabled = new CheckBox();
            this.cbxNotifyLevel = new ComboBox();
            this.lvItems = new ListBox();
            base.SuspendLayout();
            this.cbEnabled.AutoSize = true;
            this.cbEnabled.Location = new Point(12, 12);
            this.cbEnabled.Name = "cbEnabled";
            this.cbEnabled.Size = new Size(0xb9, 0x11);
            this.cbEnabled.TabIndex = 1;
            this.cbEnabled.Text = "&Warn on HTTP Protocol Violations";
            this.cbEnabled.UseVisualStyleBackColor = true;
            this.cbEnabled.Click += new EventHandler(this.cbEnabled_Click);
            this.cbxNotifyLevel.DropDownStyle = ComboBoxStyle.DropDownList;
            this.cbxNotifyLevel.FormattingEnabled = true;
            this.cbxNotifyLevel.Items.AddRange(new object[] { "Basic checks", "Extended checks" });
            this.cbxNotifyLevel.Location = new Point(0xcb, 8);
            this.cbxNotifyLevel.Name = "cbxNotifyLevel";
            this.cbxNotifyLevel.Size = new Size(0x79, 0x15);
            this.cbxNotifyLevel.TabIndex = 2;
            this.lvItems.Anchor = AnchorStyles.Right | AnchorStyles.Left | AnchorStyles.Bottom | AnchorStyles.Top;
            this.lvItems.Cursor = Cursors.Hand;
            this.lvItems.DrawMode = DrawMode.OwnerDrawVariable;
            this.lvItems.FormattingEnabled = true;
            this.lvItems.HorizontalScrollbar = true;
            this.lvItems.Location = new Point(12, 0x23);
            this.lvItems.Name = "lvItems";
            this.lvItems.SelectionMode = SelectionMode.MultiExtended;
            this.lvItems.Size = new Size(0x1f6, 0x9c);
            this.lvItems.TabIndex = 0;
            this.lvItems.KeyDown += new KeyEventHandler(this.lvItems_KeyDown);
            this.lvItems.MouseDoubleClick += new MouseEventHandler(this.lvItems_MouseDoubleClick);
            base.AutoScaleDimensions = new SizeF(6f, 13f);
          //  base.AutoScaleMode = AutoScaleMode.Font;
            base.ClientSize = new Size(0x20f, 0xcf);
            base.Controls.Add(this.lvItems);
            base.Controls.Add(this.cbxNotifyLevel);
            base.Controls.Add(this.cbEnabled);
            this.DoubleBuffered = true;
            this.Font = new Font("Tahoma", 8.25f, FontStyle.Regular, GraphicsUnit.Point, 0);
            base.KeyPreview = true;
            this.MinimumSize = new Size(360, 120);
            base.Name = "UINotifyList";
            this.Text = "Protocol Violation Report";
            base.FormClosing += new FormClosingEventHandler(this.UINotifyList_FormClosing);
            base.KeyDown += new KeyEventHandler(this.UINotifyList_KeyDown);
            base.ResumeLayout(false);
            base.PerformLayout();
        }

        private void lvItems_DrawItem(object sender, DrawItemEventArgs e)
        {
            if ((e.Index >= 0) && (e.Index < this.lvItems.Items.Count))
            {
                if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                {
                    e.Graphics.FillRectangle(Brushes.LightYellow, e.Bounds);
                }
                else
                {
                    e.Graphics.FillRectangle(Brushes.White, e.Bounds);
                }
                e.Graphics.DrawRectangle(Pens.AliceBlue, e.Bounds);
                NotifyItem item = (NotifyItem)this.lvItems.Items[e.Index];
                Rectangle layoutRectangle = new Rectangle(e.Bounds.X, e.Bounds.Y, 50, e.Bounds.Height);
                e.Graphics.DrawString("#" + item.iSessionID.ToString(), this.lvItems.Font, Brushes.Blue, layoutRectangle, sfIDColumn);
                Rectangle rectangle2 = new Rectangle(e.Bounds.X + 50, e.Bounds.Y + 3, e.Bounds.Width - 50, e.Bounds.Height);
                e.Graphics.DrawString(item.sText, this.lvItems.Font, Brushes.Black, rectangle2, StringFormat.GenericTypographic);
                e.DrawFocusRectangle();
            }
        }

        private void lvItems_KeyDown(object sender, KeyEventArgs e)
        {
            if (!e.Control)
            {
                if (e.KeyCode == Keys.Return)
                {
                    e.Handled = e.SuppressKeyPress = true;
                    this.actDoInspect();
                }
            }
            else
            {
                switch (e.KeyCode)
                {
                    case Keys.A:
                        Utilities.SendMessage(this.lvItems.Handle, 0x185, (IntPtr)1, (IntPtr)(-1));
                        e.Handled = e.SuppressKeyPress = true;
                        return;

                    case Keys.B:
                        break;

                    case Keys.C:
                        if (this.lvItems.SelectedItems.Count >= 1)
                        {
                            StringBuilder builder = new StringBuilder();
                            for (int i = 0; i < this.lvItems.SelectedItems.Count; i++)
                            {
                                NotifyItem item = (NotifyItem)this.lvItems.SelectedItems[i];
                                builder.AppendFormat("{0}\t{1}", item.iSessionID, item.sText);
                                if (i < (this.lvItems.SelectedItems.Count - 1))
                                {
                                    builder.AppendLine();
                                }
                            }
                            Utilities.CopyToClipboard(builder.ToString());
                            e.Handled = e.SuppressKeyPress = true;
                            return;
                        }
                        return;

                    case Keys.X:
                        this.lvItems.Items.Clear();
                        this.Text = string.Format("Protocol Violation Report ({0})", this.lvItems.Items.Count);
                        e.Handled = e.SuppressKeyPress = true;
                        return;

                    default:
                        return;
                }
            }
        }

        private void lvItems_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            e.ItemWidth = this.lvItems.ClientSize.Width;
            int width = e.ItemWidth - 50;
            SizeF ef = e.Graphics.MeasureString(((NotifyItem)this.lvItems.Items[e.Index]).sText, this.lvItems.Font, width, StringFormat.GenericTypographic);
            e.ItemHeight = Math.Min(0xff, ((int)Math.Ceiling((double)ef.Height)) + 6);
        }

        private void lvItems_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.actDoInspect();
        }

        public static void ReportHTTPError(int iSessionID, string sErrorDetails)
        {
            lock (qWarningsToAdd)
            {
                qWarningsToAdd.Add(new NotifyItem(iSessionID, sErrorDetails));
            }
            ScheduledTasks.ScheduleWork("UpdateHTTPErrorList", 400, new SimpleEventHandler(UINotifyList.UpdateUI));
        }

        private void UINotifyList_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (base.WindowState == FormWindowState.Normal)
            {
                FiddlerApplication.Prefs.SetInt32Pref("fiddler.ui.httperror.Top", frmProtocolViolationList.Top);
                FiddlerApplication.Prefs.SetInt32Pref("fiddler.ui.httperror.Left", frmProtocolViolationList.Left);
                FiddlerApplication.Prefs.SetInt32Pref("fiddler.ui.httperror.Width", frmProtocolViolationList.Width);
                FiddlerApplication.Prefs.SetInt32Pref("fiddler.ui.httperror.Height", frmProtocolViolationList.Height);
            }
            lock (oLock)
            {
                frmProtocolViolationList = null;
            }
        }

        private void UINotifyList_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                e.SuppressKeyPress = e.Handled = true;
                base.Close();
            }
            else if (e.KeyCode == Keys.F5)
            {
                typeof(ListBox).InvokeMember("RefreshItems", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, this.lvItems, new object[0]);
            }
        }

        internal static void UpdateUI()
        {
            if ((qWarningsToAdd.Count >= 1) && !FiddlerApplication.isClosing)
            {
                NotifyItem[] itemArray;
                if (frmProtocolViolationList == null)
                {
                    lock (oLock)
                    {
                        if (frmProtocolViolationList == null)
                        {
                            FiddlerApplication.UIInvoke(delegate
                            {
                                frmProtocolViolationList = new UINotifyList();
                                frmProtocolViolationList.Owner = FiddlerApplication.UI;
                                frmProtocolViolationList.Show(FiddlerApplication.UI);
                            });
                        }
                    }
                }
                lock (qWarningsToAdd)
                {
                    itemArray = qWarningsToAdd.ToArray();
                    qWarningsToAdd.Clear();
                }
                FiddlerApplication.UI.BeginInvoke(new LogProtocolViolation(frmProtocolViolationList.UpdateUIOnMainThread), new object[] { itemArray });
            }
        }

        private void UpdateUIOnMainThread(NotifyItem[] oItems)
        {
            if (frmProtocolViolationList != null)
            {
                frmProtocolViolationList.lvItems.Items.AddRange(oItems);
                frmProtocolViolationList.Text = string.Format("Protocol Violation Report ({0})", this.lvItems.Items.Count);
            }
        }

        protected override bool ShowWithoutActivation
        {
            get
            {
                return true;
            }
        }

        private delegate void LogProtocolViolation(UINotifyList.NotifyItem[] oItems);

        private class NotifyItem
        {
            public int iSessionID;
            public string sText;

            public NotifyItem(int iID, string sWarning)
            {
                this.iSessionID = iID;
                this.sText = sWarning;
            }
        }
    }
}

